package baseStructure;

/***
 * @author Ragnvald Fuglestein
 */

import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public abstract class Addon implements Serializable {
	private static final long serialVersionUID = -7665008819918262990L;
	protected final String name;
	public static String ANYVALUE = "ANYVALUE";
	
	protected final HashMap<String, Object> valueField = new HashMap<String, Object>();
	protected final HashMap<String, List<Object>> listField = new HashMap<String, List<Object>>();

	
	abstract public boolean checkField(Object fieldname);
	
	abstract public boolean checkField(Object fieldname, Object fieldvalue);
	
	public Addon(String name) {
		this.name = name;
	}
	
	/***
	 * 
	 * @return name of addon
	 */
	public final String getName() { return name; }

	/***
	 * Add value to the list named key
	 * @param key
	 * @param value
	 */
	protected void addListField(String key, Object value) {
		List<Object> list = listField.get(key);
		if (list == null) {
			list = new LinkedList<>();
			listField.put(key, list);
		}
		list.add(value);
	}
	
	/***
	 * Remove value from the list named key
	 * @param key
	 * @param value
	 */
	protected void removeListField(String key, Object value) {
		List<Object> list = listField.get(key);
		if (list != null) list.remove(value);
	}
	
	/***
	 * Return string containing stored variables with their values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public String getInfo() {
		String str = "";
		for (Map.Entry<String, Object> pair : valueField.entrySet()) {
			String key = pair.getKey();
			Object value = pair.getValue();
			if (value instanceof Map) {
				str += key + ": ";
				for (Map.Entry<String, Object> pair2 : ((Map<String, Object>) value).entrySet()) {
					str += pair2.getKey() + "(" + pair2.getValue() + ") ";
				}
				str += "\n";
			} else {
				str += pair.getKey() + ": " + pair.getValue() + "\n";
			}
		}
		for (Map.Entry<String, List<Object>> pair : listField.entrySet()) {
			str += pair.getKey() + ": ";
			for (Object value : pair.getValue()) {
				str += value + ", ";
			}
			str += "\n";
		}
		return str;
	}
	
	/***
	 * Overwrite addon's stored key/values ; In the case of keys with multiple values, the existing value is kept
	 * @param addon
	 */
	@SuppressWarnings("unchecked")
	public void merge(Addon addon) {
		for (Map.Entry<String, Object> pair : addon.valueField.entrySet()) {
			String key = pair.getKey();
			Object value = pair.getValue();
			Object oldValue = valueField.get(key);
			if (oldValue == null) {
				valueField.put(key, value);
				continue;
			}
			if (value instanceof Map) { // Assume oldValue is of same type
				for (Map.Entry<String, Object> pair2 : ((Map<String, Object>) value).entrySet()) {
					((Map<String, Object>) oldValue).put(pair2.getKey(), pair2.getValue());
				}
			} else { valueField.put(key, value); }
		}
		
		for (Map.Entry<String, List<Object>> pair : addon.listField.entrySet()) {
			String key = pair.getKey();
			List<Object> list = pair.getValue();
			List<Object> oldList = listField.get(key);
			if (oldList == null) {
				listField.put(key, list);
				continue;
			}
			for (Object o : list) {
				if (!(oldList.contains(o))) oldList.add(o);
			}
		}
	}
}
